package com.zq.it.cms.common;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.transaction.annotation.Transactional;

import com.zq.it.cms.common.util.CommUtil;



/**
 * @author 郑强
 * 基础Service类     Repository必须继承 BaseRepository接口
 */
@SuppressWarnings("unchecked")
public class BaseService<Repository extends BaseRepository<Entity>, Entity> {
	
	@Autowired
	private Repository repository;
	
	@Autowired
	private EntityManagerFactory entityManagerFactory;
	
	/**
	 * 新增/修改
	 */
	@Transactional(readOnly = false)
	public Entity save(Entity entity){
		return ((JpaRepository<Entity, Long>)repository).save(entity);
	}
	
	/**
	 * 根据ID查找
	 */
	public Entity findById(Long id){
		return ((JpaRepository<Entity, Long>)repository).findOne(id);
	}
	
	/**
	 * 根据ID删除
	 */
	@Transactional(readOnly = false)
	public void delete(Long id){
		((JpaRepository<Entity, Long>)repository).delete(id);
	}
	
	/**
	 * 根据ID批量删除
	 */
	@Transactional(readOnly = false)
	public void delete(Long[] ids){
		for (Long id : ids) {
			((JpaRepository<Entity, Long>)repository).delete(id);
		}
	}
	
	/**
	 * 根据ID列表查询
	 */
	public List<Entity> findByIds(Long[] ids){
		return ((JpaRepository<Entity, Long>)repository).findAll(Arrays.asList(ids));
	}
	/**
	 * 根据SQL查询数据，返回map类型
	 */
	public List<Map<String, Object>> findMapBySql(String sql, Map<String, Object> params){
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		Session session = entityManager.unwrap(Session.class);
		Query query = session.createSQLQuery(sql);
		if(params!=null && !params.isEmpty()){
			for (String name : params.keySet()) {
				query.setParameter(name, params.get(name));
			}
		}
		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		List<Map<String, Object>> list = query.list();
		entityManager.close();
		return list;
	}
	
	/**
	 * 根据sql查询分页
	 */
	public Page<Map<String, Object>> findMapPageBySql(String sql, Map<String, Object> params, Pageable page){
		int total = findCount(sql, params);
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		Session session = entityManager.unwrap(Session.class);
		Query query = session.createSQLQuery(sql);
		if(params!=null && !params.isEmpty()){
			for (String name : params.keySet()) {
				query.setParameter(name, params.get(name));
			}
		}
		query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
		if(page != null){
			query.setFirstResult(page.getOffset());
			query.setMaxResults(page.getPageSize());
		}
		List<Map<String, Object>> list = query.list();
		if(page == null){
			total = list.size();
		}
		Page<Map<String, Object>> pageInfo = new PageImpl<>(list, page, total);
		entityManager.close();
		return pageInfo;
	}
	
	/**
	 * 查询条数
	 */
	public int findCount(String sql, Map<String, Object> params){
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		Session session = entityManager.unwrap(Session.class);
		Query query = session.createSQLQuery("select count(*) from (" + sql + ") __counter");
		if(params!=null && !params.isEmpty()){
			for (String name : params.keySet()) {
				query.setParameter(name, params.get(name));
			}
		}
		int result = Integer.valueOf(query.uniqueResult().toString());
		entityManager.close();
		return result;
	}
	
	/**
	 * 只查询一条记录
	 */
	public Entity findOne(Map<String, Object> params){
		List<Entity> list = findAllByParams(params);
		if(list.size() > 1){
			throw new RuntimeException("查询到多条结果");
		}
		return list.size() > 0 ? list.get(0) : null;
	}
	
	/**
	 * 查询最前面的一条记录
	 */
	public Entity findTopOne(Map<String, Object> params, Sort sort){
		List<Entity> list = findAllByParams(params, sort);
		return list.size() > 0 ? list.get(0) : null;
	}
	
	/**
	 * 根据条件查询条数
	 */
	public long countByParams(Map<String, Object> params){
		return ((JpaSpecificationExecutor<Entity>)repository).count(new MapSpecification<Entity>(params == null ? new HashMap<String, Object>() : params, null));
	}
	
	/**
	 * 根据搜索条件分页查询
	 */
	public Page<Entity> findPageByParams(final Map<String, Object> params, Pageable page){
		final Sort sort = page.getSort();//获取到排序信息，自己处理
		return ((JpaSpecificationExecutor<Entity>)repository).findAll(new MapSpecification<Entity>(params == null ? new HashMap<String, Object>() : params, sort), new PageRequest(page.getPageNumber(), page.getPageSize()));
	}
	
	/**
	 * 根据搜索条件查询所有
	 */
	public List<Entity> findAllByParams(final Map<String, Object> params){
		return findAllByParams(params, null);
	}
	
	/**
	 * 根据搜索条件查询所有并排序
	 */
	public List<Entity> findAllByParams(final Map<String, Object> params, final Sort sort){
		return ((JpaSpecificationExecutor<Entity>)repository).findAll(new MapSpecification<Entity>(params == null ? new HashMap<String, Object>() : params, sort));
	}
	
	public Entity convertMapToEntity(Map<String,Object> map){
		Class<?> claz = getEntityType();
		map = CommUtil.changeKeyNamesToCamel(map);
		try {
			Entity obj = (Entity) claz.newInstance();
			List<String> keys = new ArrayList<>();
			for(String key:map.keySet()){
				if(map.get(key) == null){
					keys.add(key);
				}
			}
			for(String key: keys){
				map.remove(key);
			}
			BeanUtils.populate(obj, map);
			return obj;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	/**
	 * map集合转实体类集合
	 */
	public List<Entity> mapToEntity(List<Map<String,Object>> list){
		List<Entity> dataList = new ArrayList<>();
		Class<?> claz = getEntityType();
		if(list != null && !list.isEmpty()){
			for (Map<String, Object> map : list) {
				map = CommUtil.changeKeyNamesToCamel(map);
				try {
					Entity obj = (Entity) claz.newInstance();
					List<String> keys = new ArrayList<>();
					for(String key:map.keySet()){
						if(map.get(key) == null){
							keys.add(key);
						}
					}
					for(String key: keys){
						map.remove(key);
					}
					BeanUtils.populate(obj, map);
					dataList.add(obj);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return dataList;
	} 
	
	/**
	 * map集合转实体类集合
	 */
	public <T extends Object> List<T>  mapToEntity(List<Map<String,Object>> list, Class<T> claz){
		List<T> dataList = new ArrayList<>();
		if(list != null && !list.isEmpty()){
			for (Map<String, Object> map : list) {
				map = CommUtil.changeKeyNamesToCamel(map);
				try {
					T obj = (T) claz.newInstance();
					List<String> keys = new ArrayList<>();
					for(String key:map.keySet()){
						if(map.get(key) == null){
							keys.add(key);
						}
					}
					for(String key: keys){
						map.remove(key);
					}
					BeanUtils.populate(obj, map);
					dataList.add(obj);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return dataList;
	} 
	
	/**
	 * 获取当前实体类类对象
	 */
	public Class<?> getEntityType(){
		Type t = this.getClass().getGenericSuperclass();  
        //获取泛型参数的实际类型 
		Class<?> claz = (Class<?>)(((ParameterizedType)t).getActualTypeArguments()[1]);
		return claz;
	}
	
	public Repository getRepository(){
		return repository;
	}

	public void setRepository(Repository repository) {
		this.repository = repository;
	}
	
	public boolean notEmpty(Map<String, Object> params, String key){
		if(params.containsKey(key)){
			if(params.get(key) != null){
				if(StringUtils.isNotBlank(params.get(key).toString())){
					return true;
				}
			}
		}
		return false;
	}
}
